/*
 * Copyright (c) 2009.
 * nick@tmro.net
 */
package net.tmro.loko.ejb.dao.jpa;

import net.tmro.loko.ejb.dao.Dao;

import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceContext;
import java.lang.reflect.ParameterizedType;

/**
 * Generic JPA mplementation of the Dao class. Each entity  should extent this and then add specific Dao
 * methods (e.g findAfterDate).
 * <p/>
 * The EntityManager is injected via the @PersistenceContext.
 *
 * @param <K> the primary key type
 * @param <E> the entity type
 */
public abstract class JpaDao<K, E> implements Dao<K, E> {
    /**
     * Used to get the class name in queries and also when finding by id.
     * Is protected so that children have access to it.
     */
    protected Class<E> entityClass;

    @PersistenceContext(unitName = "MainLokoPeristenceUnit")
    protected EntityManager entityManager;

    /**
     * Default constructor responsible with setting the #entityClass from the superclass generic
     */
    public JpaDao() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
        this.entityClass = (Class<E>) genericSuperclass.getActualTypeArguments()[1];
    }

    public void persist(E entity) {
        entityManager.persist(entity);
    }

    public void remove(E entity) {
        entityManager.remove(entityManager.merge(entity));
    }

    public E findById(K id) {
        return entityManager.find(entityClass, id);
    }

    /**
     * Calls #findById and if null is returned (no entity found) then it throws an EntityNotFoundException.
     *
     * @param id unique identifier of the object to find
     * @return the entity returned by #findById
     * @throws javax.persistence.EntityNotFoundException
     *
     */
    public E getById(K id) throws EntityNotFoundException {
        E entity = entityManager.find(entityClass, id);
        if (entity == null) {
            throw new EntityNotFoundException("Entity " + entityClass.getName() + " with id " + id + " not found");
        }
        return entity;
    }

    /**
     * TODO remove this since it is only used for Unit Testing. Check to see if there is a better way
     *
     * @return
     */
    public EntityManager getEntityManager() {
        return entityManager;
    }

    /**
     * TODO remove this setter. It only exists for ease of Unit Testing. Check to see if it can be replaced with JNDI settings or someting else.
     *
     * @param entityManager
     */
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }
}